home *** CD-ROM | disk | FTP | other *** search
- /*==============================================================================
- Project: POV-Ray
-
- Version: 3
-
- File: ImageWindow.c
-
- Description:
- This file contains the Macintosh Image window routines for POV-Ray.
- ------------------------------------------------------------------------------
- Authors:
- Jim Nitchals, David Harr, Eduard [esp] Schwan
- ------------------------------------------------------------------------------
- from Persistence of Vision(tm) Ray Tracer
- Copyright 1996 Persistence of Vision Team
- ------------------------------------------------------------------------------
- NOTICE: This source code file is provided so that users may experiment
- with enhancements to POV-Ray and to port the software to platforms other
- than those supported by the POV-Ray Team. There are strict rules under
- which you are permitted to use this file. The rules are in the file
- named POVLEGAL.DOC which should be distributed with this file. If
- POVLEGAL.DOC is not available or for more info please contact the POV-Ray
- Team Coordinator by leaving a message in CompuServe's Graphics Developer's
- Forum. The latest version of POV-Ray may be found there as well.
-
- This program is based on the popular DKB raytracer version 2.12.
- DKBTrace was originally written by David K. Buck.
- DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
- ------------------------------------------------------------------------------
- Change History:
- 930610 [esp] Created
- 930610 [esp] Added Size2Window code
- 930620 [esp] Changed brighten/darken image slightly to fix saturation bug
- 930710 [esp] Added WindowValid check
- 930903 [esp] Major bug fixes to Virtual Image Buffer code
- 931001 [esp] version 2.0 finished (Released on 10/4/93)
- 931119 [djh] 2.0.1 source conditionally compiles for PPC machines, keyword __powerc
- 940416 [PFS] 2.2.1 greatly reworked to clean up PPC support and provide CodeWarrior projects
- 960704 [esp] 3.0b7k redid VIB buffer to be a whole # of scanlines to fix a bug
- 960706 [esp] Changed offscreen from old pixmaps to new GWorlds, now images can be bigger than 4Kx4K!
- ==============================================================================*/
-
- /*==== our header ====*/
- #include "ImageWindow.h"
-
-
- /*==== POV Mac Library routines =====*/
- #include "UtilLib.h"
-
-
- /*==== Compress PICT routines ====*/
- #include "SaveCmpPict.h"
-
- #include "AppPrefs.h" // APGet_AddCustomIcons()
- #include "FilePrefs.h"
- #include "ProgressDialog.h"
-
- #include <finder.h> // FInfo
- #include <strings.h> // c2pstr
-
- /*==== defs ====*/
-
- // temp virtual image file file
- #define POVRAY_IMAGETEMP_FNAME "POV-Ray.vib"
-
- // Windows
- #define kWindID_Image 1001 // image window resource ID
-
- #define PICTF_HEADER_SIZE 512 // old MacDraw PICTF header size in bytes
-
- /* Pict file header structure (after the 512 byte header) */
- typedef struct
- {
- short picSize; // low word of size
- Rect picFrame; // picture bounds
- } PictFHeader, *PictFHeaderPtr;
-
-
- /*==== globals ====*/
-
- WindowPtr gImageWindowPtr = NULL; // the image window
- Boolean gImageWindIsValid = false; // true if valid stuff in window
- Boolean gUsingCustomPalette = false; // does the user desire to use color q?
- int gColorQuantMethod = -1; // what kind of color quantization?
- Boolean gTooBigForPICT = false; // true if X size too big to save/display as PICT
- Boolean gDoingVirtualFile = false; // true if doing virtual image buffering
-
-
- /*==== globals (local) ====*/
-
- /* image window stuff */
- static GWorldPtr gOffScreenGWPtr = NULL;
-
- static PaletteHandle gCustomPalette = NULL;
- static PaletteHandle gSystemPalette = NULL;
-
- // used by Paint_to_Picture() and MyPutPicProc()
- static PicHandle gMyPicHandle;
- static long gMyPicSize;
-
- static FILE *gImagePictFile = NULL; // used to save image to PICT
- static Rect gImageBounds, // source (offscreen image) bounds
- gDisplayBounds; // destination image bounds
- static long gImageWidth, // user-requested image size
- gImageHeight;
- static long gLastYPos = 0; // last vertical position during previous refresh
- static long gCurrYPos;
- static long gPixMapBuffSize;
- static long gDitherTicks; // # of ticks to wait between image refresh
- static long gRefreshTick = 0; // Time of last Quickdraw dither of graphic port
- static Boolean gBusySavingImage = FALSE; // true while in the save code, prevent reentrancy
-
- // Undo stuff
- // static Ptr gImageUndoBuffer = NULL;
- // static Ptr gImageUndoBuffer2 = NULL;
- // static Ptr gImageRevertBuffer = NULL;
-
- // virtual image buffer globals
- static FILE *gVirtualImageFile = NULL;
- static long gVIBPixHeight;
- static Boolean gVIBIsDirty;
- static long gVIBCurrSegmentIndex = -1;
- static long gVIBMinY;
- static long gVIBMaxY;
-
-
- static void CalcVIBSegmentIndexes(short y);
-
-
- // ==============================================
- void InitImageWindow(void)
- {
- // allocate the image window (it is shown/hidden later)
- gImageWindowPtr = GetNewCWindow(kWindID_Image, NULL, (WindowPtr)NULL);
- } // InitImageWindow
-
-
- // ==============================================
- void KillImageWindow(void)
- {
- if (gImageWindowPtr)
- DisposeWindow(gImageWindowPtr);
- gImageWindowPtr = NULL;
- } // KillImageWindow
-
-
-
- // ==============================================
- // Create system/custom palette variables for use by image window
- void SetupPalettes(void)
- {
- int k;
-
- // Get default System palette for non-custom mode, (IM VI, Pg. 20-17)
- gSystemPalette = NewPalette(256, NULL, pmTolerant, 0x0000);
- if (gSystemPalette)
- {
- CopyPalette(GetPalette((WindowPtr)-1), gSystemPalette, 0, 0, 256);
- for (k=0; k<256; k++)
- SetEntryUsage(gSystemPalette, k, pmTolerant, 0x0000);
- }
-
- // allocate a palette for the Image window, fill to default system palette
- gCustomPalette = NewPalette(256, NULL, pmTolerant, 0x0000); // exact match only
- if (gCustomPalette)
- {
- CopyPalette(gSystemPalette, gCustomPalette, 0, 0, 256);
- for (k=0; k<256; k++)
- SetEntryUsage(gCustomPalette, k, pmTolerant, 0x0000);
- }
- } // SetupPalettes
-
- // ==============================================
- // Calculate # of bytes used by a particular size of offscreen grafport
- long CalcPixMapSize(long imageWidth, short imageHeight)
- {
- // do rowbytes-like rounding calculation
- return (((imageWidth+4L)>>2)<<2) * imageHeight * 4;
- }
-
- // ==============================================
- // Build offscreen image buffer
- void SetupOffscreen(void)
- {
- OSErr anError = noErr;
- GWorldPtr saveGWorld;
- GDHandle saveGD;
-
- // don't allow static buildup!
- if (gOffScreenGWPtr)
- KillOffscreen();
-
- GetGWorld(&saveGWorld, &saveGD);
-
- if (gDoingVirtualFile)
- {
- // set up VIB stuff
- gVIBPixHeight = 16; // Just do 16 scanlines at a time
- gCurrYPos = 0;
- gLastYPos = -1;
- gVIBIsDirty = false;
- CalcVIBSegmentIndexes(gCurrYPos);
- gPixMapBuffSize = CalcPixMapSize(gImageWidth, gVIBPixHeight);
- SetRect(&gImageBounds, 0, 0, gImageWidth, gVIBPixHeight);
- }
- else
- {
- gPixMapBuffSize = CalcPixMapSize(gImageWidth, gImageHeight);
- SetRect(&gImageBounds, 0, 0, gImageWidth, gImageHeight);
- }
-
- // create offscreen pixmap to write into
- anError = NewGWorld(&gOffScreenGWPtr, 32, &gImageBounds, NULL, NULL, 0);
-
- if (!anError)
- {
- PixMapHandle aPixMapH;
- SetGWorld(gOffScreenGWPtr, NULL);
- // Here's a really skanky thing to do to allow an alpha channel in PICTs
- // Let's hope it works! [esp]
- aPixMapH = GetGWorldPixMap(gOffScreenGWPtr);
- if ((**gPrefs2Use_h).doAlphaChannel)
- {
- (**aPixMapH).cmpCount = 4; // from RGB to RGBA!
- PortChanged(qd.thePort); // tell QD to notice the cmpCount change (3.0.1)
- }
- // Clear it
- EraseRect(&gImageBounds);
- SetGWorld((CGrafPtr)saveGWorld, saveGD);
- }
- else
- {
- // fatal error
- DisplayModalDialog(kdlog_GenericFatalErr, ok, 0,
- "Cannot allocate memory for offscreen image buffer",
- anError, ewcDoCentering, eMainDevice);
- exit_handler();
- }
- } // SetupOffscreen
-
-
- // ==============================================
- // Delete offscreen image buffer
- void KillOffscreen(void)
- {
- if (gOffScreenGWPtr)
- DisposeGWorld(gOffScreenGWPtr);
- gOffScreenGWPtr = NULL;
- } // KillOffscreen
-
-
- // ==============================================
- // Return Pixmap within the gworld passed, and lock it down for use
- static PixMapHandle LockAndLoadPixMap(GWorldPtr aGWorldPtr)
- {
- PixMapHandle aPixMapH = NULL;
- if (gOffScreenGWPtr)
- {
- aPixMapH = GetGWorldPixMap(aGWorldPtr);
- if (aPixMapH)
- LockPixels(aPixMapH);
- }
- return aPixMapH;
- }
-
-
- // ==============================================
- // Unlock the passed Pixmap
- static void UnlockPixMap(PixMapHandle aPixMapH)
- {
- if (aPixMapH)
- UnlockPixels(aPixMapH);
- }
-
-
- // ==============================================
- // Set the image window name
- static void SetImageWindowTitle(StringPtr theFileName)
- {
- if (gImageWindowPtr)
- SetWTitle(gImageWindowPtr, theFileName);
- } // SetImageWindowTitle
-
-
- // ==============================================
- // Close the image window
- void CloseImageWindow()
- {
- if (gImageWindowPtr)
- HideWindow(gImageWindowPtr);
- (**gFilePrefs_h).imageMagFactor = viewmn_hidden;
- } // CloseImageWindow
-
-
- // ==============================================
- // Force the entire image window to be updated
- void InvalRect_ImageWindow(Boolean DoWholeWindow)
- {
- int magFactor;
- Rect myInvalRect;
- RgnHandle theClip;
-
- if (gImageWindowPtr && ((WindowPeek)gImageWindowPtr)->visible)
- {
- SetPort(gImageWindowPtr);
-
- theClip = NewRgn();
- GetClip(theClip); // save old clip region
- myInvalRect = gImageWindowPtr->portRect;
- ClipRect(&myInvalRect); // change clip region
-
- // if doing partial window in a regular magnification mode...
- if (!DoWholeWindow && ((**gPrefs2Use_h).imageMagFactor != viewmn_Size2Window))
- {
- // no magnification allowed in VIB mode!
- if (gDoingVirtualFile)
- magFactor = 1;
- else
- magFactor = (**gPrefs2Use_h).imageMagFactor-viewmn_normal+1; // 1,2,3,4
- myInvalRect.top = magFactor * gLastYPos;
- myInvalRect.bottom = magFactor * (gCurrYPos + 1);
- }
- InvalRect(&myInvalRect);
-
- SetClip(theClip); // restore old clip region
- DisposeRgn(theClip);
-
- }
- } // InvalRect_ImageWindow
-
-
- // ==============================================
- // Display the image window grow box
- static void DrawImageGrowBox(void)
- {
- int looper;
- Rect box;
- // PenState pstate;
-
- // Save current port state
- // SetPort(gImageWindowPtr);
- // GetPenState(&pstate);
-
- // find window size
- box = gImageWindowPtr->portRect;
-
- // make boxes in lower left corner
- box.top = box.bottom-7;
- box.left = box.right-7;
- OffsetRect(&box, -1, -1);
-
- // do two overlapping boxes
- for (looper=0; looper<2; looper++)
- {
- // draw white box
- ForeColor(whiteColor);
- FrameRect(&box);
-
- // draw black box
- OffsetRect(&box, -1, -1);
- ForeColor(blackColor);
- FrameRect(&box);
-
- // move up & draw 2nd smaller box
- OffsetRect(&box, -2, -2);
- box.right -= 1;
- box.bottom -= 1;
- }
-
- // restore world
- // SetPenState(&pstate);
- } // DrawImageGrowBox
-
-
- // ==============================================
- // Display the image to the window (assumes port set to window)
- static void DrawImageWindow(Boolean DoWholeWindow)
- {
- static short counter = 0;
- RGBColor myRGBWhite = {-1,-1,-1};
- RGBColor myRGBBlack = {0,0,0};
-
- ShowWatchCursor(); // could take a little while..
-
- if ((**gPrefs2Use_h).imageMagFactor != viewmn_hidden)
- { // it is visible
-
- // set these to defaults so copybits behaves predictably
- RGBBackColor(&myRGBWhite);
- RGBForeColor(&myRGBBlack);
-
- if (DoWholeWindow)
- {
- // clear whole window
- EraseRect(&gImageWindowPtr->portRect);
- }
-
- // something to display?
- if (gOffScreenGWPtr)
- {
- short myMode;
- PixMapHandle aPixMapH = NULL;
-
- // if (gHasPictUtils)
- // SetCustomPalette(false);
-
- if ((**gPrefs2Use_h).doDither)
- myMode = ditherCopy;
- else
- myMode = srcCopy;
-
- if (gDoingVirtualFile)
- { // VIB - display each segment to the window
- int k;
- Rect vibRect,windRect;
- // set up source (VIB) rect... use window width for copybits width
- vibRect = gImageWindowPtr->portRect;
- vibRect.top = 0;
- vibRect.bottom = gVIBPixHeight;
- // set up destination rect sides
- windRect = gImageWindowPtr->portRect;
- for (k=0; k < gImageWindowPtr->portRect.bottom; k+=gVIBPixHeight)
- {
- swap_virtual_segment (k);
- // set up destination rect top/bottom
- windRect.top = k;
- windRect.bottom = k + gVIBPixHeight;
- // Get a handle to the offscreen pixmap area
- aPixMapH = LockAndLoadPixMap(gOffScreenGWPtr);
- CopyBits((BitMap*)*aPixMapH, &gImageWindowPtr->portBits,
- &vibRect, &windRect,
- myMode, NULL);
- // all done with the offscreen pixmap area
- UnlockPixMap(aPixMapH);
- }
- }
- else
- { // blast whole thing to the window
- // Get a handle to the offscreen pixmap area
- aPixMapH = LockAndLoadPixMap(gOffScreenGWPtr);
- // display it
- CopyBits((BitMap*)*aPixMapH, &gImageWindowPtr->portBits,
- &gImageBounds, &gDisplayBounds,
- myMode, NULL);
- // all done with the offscreen pixmap area
- UnlockPixMap(aPixMapH);
- }
-
- // Draw our custom size box if in Size-2-Window mode
- if ((**gPrefs2Use_h).imageMagFactor == viewmn_Size2Window)
- DrawImageGrowBox();
-
-
- } // offscreen exists
-
- } // it is visible
-
- ShowArrowCursor();
-
- } // DrawImageWindow
-
-
- // ==============================================
- void DoResizeImageWindow(WindowPtr w, short h, short v)
- {
- Rect r;
-
- SetPort(w);
-
- SizeWindow(w, h, v, false);
-
- GetGlobalWindowRect(w, &r);
- (**gFilePrefs_h).imageWind_pos = r;
- if ((**gPrefs2Use_h).imageMagFactor == viewmn_Size2Window)
- gDisplayBounds = w->portRect;
-
- } // DoResizeImageWindow
-
-
- // ==============================================
- void DoGrowImageWindow(WindowPtr w, Point p)
- {
- GrafPtr savePort;
- long theResult;
- Rect r;
-
- GetPort(&savePort);
- SetPort(w);
-
- GetMaxGrowRect(w, &r);
- theResult = GrowWindow(w, p, &r);
- if (theResult != 0)
- {
- DoResizeImageWindow(w, LoWord(theResult), HiWord(theResult));
- InvalRect_ImageWindow(true);
- }
-
- SetPort(savePort);
- } // DoGrowImageWindow
-
-
- // ==============================================
- void UpdateImageWindow(void)
- {
- if (gImageWindowPtr)
- {
- SetPort(gImageWindowPtr);
- BeginUpdate(gImageWindowPtr);
- DrawImageWindow(false);
- EndUpdate(gImageWindowPtr);
- }
- } // UpdateImageWindow
-
-
- // ==============================================
- void SetImageWindowMag(short magMenuItem)
- {
- int magFactor;
- Rect r,screenRect;
- GDHandle theGD;
-
- if (magMenuItem == viewmn_hidden)
- HideWindow(gImageWindowPtr);
- else
- {
- if (magMenuItem == viewmn_Size2Window)
- { // set image buffer to 1xsize, leave window size alone
- gDisplayBounds = gImageWindowPtr->portRect;
- }
- else
- { // set image buffer rect to N*Size, resize window
- // no magnification allowed in VIB mode!
- if (gDoingVirtualFile)
- magFactor = 1; // only 1x
- else
- magFactor = magMenuItem-viewmn_normal+1; // 1,2,3,4
- // get new zero-based rect
- SetRect(&gDisplayBounds, 0, 0,
- gImageWidth * magFactor,
- gImageHeight * magFactor);
- // convert to potential global window rect
- GetGlobalWindowRect(gImageWindowPtr, &r);
- r.right = r.left + gDisplayBounds.right;
- r.bottom = r.top + gDisplayBounds.bottom;
- // move it to appropriate screen if needed
- ForceRectOnScreen(&r);
- // [esp] hmm, shouldn't this next useful chunk of code be moved into ScreenUtils.c?
- // clip any overhang off bottom/right
- theGD = GetClosestGDevice(&r);
- screenRect = (**theGD).gdRect;
- if (r.right > screenRect.right)
- r.right = screenRect.right;
- if (r.bottom > screenRect.bottom)
- r.bottom = screenRect.bottom;
- MoveWindow(gImageWindowPtr, r.left, r.top, false);
- DoResizeImageWindow(gImageWindowPtr,
- r.right-r.left,
- r.bottom-r.top);
- // [esp] need code here to handle scroll bars... oh yah, we need scroll bars first!
- }
-
- // if window is valid, show it now. This check lets the user
- // set the window size even when there's no valid window content,
- // and doesn't actually show the window until it is valid.
- if (gImageWindIsValid)
- {
- ShowWindow(gImageWindowPtr);
- SelectWindow(gImageWindowPtr);
- InvalRect_ImageWindow(true);
- }
- } // else visible
- } // SetImageWindowMag
-
- // ==============================================
- // ==============================================
- #ifdef PHASE_OUT
- // These were retouching tools put into 1.0 and 2.0 by Jim Nitchals for small images,
- // but it is dangerous when we switch to VIBs (and GWorlds after 3.0), so they're
- // being phased out... but the source code remains in 3.0 for the curious.
-
-
- // ==============================================
- // Create undo buffers for Image window changes
- void make_undo(void)
- {
- if (gImageUndoBuffer == 0)
- {
- gImageUndoBuffer = NewPtr (gPixMapBuffSize); /* room for image */
- gImageUndoBuffer2 = NewPtr (gPixMapBuffSize); /* room for image */
- gImageRevertBuffer = NewPtr (gPixMapBuffSize);
- if ( (gImageRevertBuffer) && (gImagePixmapPtr))
- memcpy(gImageRevertBuffer, gImagePixmapPtr, gPixMapBuffSize);
- }
-
- /* if any of the memory allocations failed, or available mem is low, */
- /* fail the whole undo system */
- if ( (gImageUndoBuffer == NULL) || (gImageUndoBuffer2 == NULL) || (gImageRevertBuffer == NULL)
- || (FreeMem() < 50000L) )
- {
- if (gImageUndoBuffer)
- DisposePtr (gImageUndoBuffer);
- if (gImageUndoBuffer2)
- DisposePtr (gImageUndoBuffer2);
- if (gImageRevertBuffer)
- DisposePtr (gImageRevertBuffer);
- gImageUndoBuffer = NULL;
- gImageUndoBuffer2 = NULL;
- gImageRevertBuffer = NULL;
- }
-
- if ((gImageUndoBuffer) && (gImagePixmapPtr))
- {
- memcpy(gImageUndoBuffer, gImagePixmapPtr, gPixMapBuffSize);
- gCanUndo = TRUE;
- }
- } // make_undo
-
-
- // ==============================================
- // Actually do the undo operation on the image window
- void undo_image(void)
- {
- if ((gImageUndoBuffer) && (gCanUndo) && (gImagePixmapPtr))
- {
- memcpy(gImageUndoBuffer2, gImagePixmapPtr, gPixMapBuffSize);
- memcpy(gImagePixmapPtr, gImageUndoBuffer, gPixMapBuffSize);
- memcpy(gImageUndoBuffer, gImageUndoBuffer2, gPixMapBuffSize);
- InvalRect_ImageWindow(true);
- }
- } // undo_image
-
-
- // ==============================================
- // restore the original image to the image window
- void revert_image(void)
- {
- if ((gImageRevertBuffer) && (gImagePixmapPtr))
- {
- memcpy(gImageUndoBuffer, gImagePixmapPtr, gPixMapBuffSize);
- memcpy(gImagePixmapPtr, gImageRevertBuffer, gPixMapBuffSize);
- gCanUndo = TRUE;
- InvalRect_ImageWindow(true);
- }
- } // revert_image
-
-
-
- // ==============================================
- // return the value "v", insuring it is between 0 and 255
- static short ClipToByteRange(short v)
- {
- if ( v < 0)
- return (0);
- if (v > 255)
- return (255);
- return (v);
- } // ClipToByteRange
-
-
- // ==============================================
- // Darken every pixel value in image window by 7/8ths original
- void darken_image(void)
- {
- unsigned char *pptr;
- short v;
- long i,j;
-
- make_undo();
- if (gImagePixmapPtr == 0) return;
-
- for (i=0; i < gImageHeight; i++)
- {
- for (j=0; j < gImageWidth; j++)
- {
- pptr = (unsigned char *)
- (gImagePixmapPtr + 4L * ((gImageWidth * i) + j));
- *pptr = 0;
- pptr++;
- v = (*pptr * 7 / 8)-1;
- *pptr = ClipToByteRange (v);
- pptr++;
- v = (*pptr * 7 / 8)-1;
- *pptr = ClipToByteRange (v);
- pptr++;
- v = (*pptr * 7 / 8)-1;
- *pptr = ClipToByteRange (v);
- pptr++;
- }
- }
- InvalRect_ImageWindow(true);
-
- } // darken_image
-
-
- // ==============================================
- // Lighten every pixel value in image window by 8/7ths original
- void lighten_image(void)
- {
- unsigned char *pptr;
- long i,j;
- short v;
-
- make_undo();
- if (gImagePixmapPtr == 0) return;
-
- for (i=0; i < gImageHeight; i++)
- {
- for (j=0; j < gImageWidth; j++)
- {
- pptr = (unsigned char *)
- (gImagePixmapPtr + 4L * ((gImageWidth * i) + j));
- *pptr = 0;
- pptr++;
- v = (*pptr * 8 / 7)+1;
- *pptr = ClipToByteRange (v);
- pptr++;
- v = (*pptr * 8 / 7)+1;
- *pptr = ClipToByteRange (v);
- pptr++;
- v = (*pptr * 8 / 7)+1;
- *pptr = ClipToByteRange (v);
- pptr++;
- }
- }
- InvalRect_ImageWindow(true);
-
- } // lighten_image
-
-
- // ==============================================
- // Invert every pixel value in image window
- void invert_image(void)
- {
-
- unsigned char *pptr;
- long i,j;
-
- make_undo();
- if (gImagePixmapPtr == 0) return;
-
- for (i=0; i < gImageHeight; i++)
- {
- for (j=0; j < gImageWidth; j++)
- {
- pptr = (unsigned char *)
- (gImagePixmapPtr + 4L * ((gImageWidth * i) + j));
- *pptr = 0;
- pptr++;
- *pptr = 255 - *pptr;
- pptr++;
- *pptr = 255 - *pptr;
- pptr++;
- *pptr = 255 - *pptr;
- pptr++;
- }
- }
- InvalRect_ImageWindow(true);
-
- } // invert_image
-
-
- // ==============================================
- // Reduce the contrast of every pixel value in image window a bit
- void reduce_contrast(void)
- {
- unsigned char *pptr;
- long i,j;
- short v;
-
- make_undo();
- if (gImagePixmapPtr == 0) return;
-
- for (i=0; i < gImageHeight; i++)
- {
- for (j=0; j < gImageWidth; j++)
- {
- pptr = (unsigned char *)
- (gImagePixmapPtr + 4L * ((gImageWidth * i) + j));
- *pptr++ = 0;
-
- v = *pptr;
- v = v - ((v - 128) >> 2);
- *pptr++ = v;
-
- v = *pptr;
- v = v - ((v - 128) >> 2);
- *pptr++ = v;
-
- v = *pptr;
- v = v - ((v - 128) >> 2);
- *pptr++ = v;
- }
- }
- InvalRect_ImageWindow(true);
-
- } // reduce_contrast
-
-
- // ==============================================
- // Increase the contrast of every pixel value in image window a bit
- void increase_contrast(void)
- {
- unsigned char *pptr;
- long i,j;
- short v;
-
- make_undo();
- if (gImagePixmapPtr == 0) return;
-
- for (i=0; i < gImageHeight; i++)
- {
- for (j=0; j < gImageWidth; j++)
- {
- pptr = (unsigned char *)
- (gImagePixmapPtr + 4L * ((gImageWidth * i) + j));
- *pptr++ = 0;
-
- v = *pptr;
- v = v + ((v - 128) >> 2);
- *pptr++ = ClipToByteRange(v);
-
- v = *pptr;
- v = v + ((v - 128) >> 2);
- *pptr++ = ClipToByteRange(v);
-
- v = *pptr;
- v = v + ((v - 128) >> 2);
- *pptr++ = ClipToByteRange(v);
- }
- }
- InvalRect_ImageWindow(true);
-
- } // increase_contrast
-
-
- // ==============================================
- // draw a 1 pixel black border around the edge of the image
- void draw_border(void)
- {
- unsigned char *pptr;
- long i;
-
- make_undo();
- if (gImagePixmapPtr == 0) return;
-
- for (i=0; i < gImageHeight; i++)
- {
- /* left border edge */
- pptr = (unsigned char *)
- (gImagePixmapPtr + (gImageWidth * 4 * i) );
- *pptr++ = 0;
- *pptr++ = 0;
- *pptr++ = 0;
- *pptr++ = 0;
-
- /* right border edge */
- pptr = (unsigned char *)
- (gImagePixmapPtr + (gImageWidth * 4 * i) + ((gImageWidth-1) * 4) );
- *pptr++ = 0;
- *pptr++ = 0;
- *pptr++ = 0;
- *pptr++ = 0;
- }
- for (i=0; i < gImageWidth; i++)
- {
- /* top border edge */
- pptr = (unsigned char *)
- (gImagePixmapPtr + (4 * i));
- *pptr++ = 0;
- *pptr++ = 0;
- *pptr++ = 0;
- *pptr++ = 0;
-
- /* bottom border edge */
- pptr = (unsigned char *)
- ( gImagePixmapPtr + 4L*gImageWidth*(gImageHeight-1) + 4*i );
- *pptr++ = 0;
- *pptr++ = 0;
- *pptr++ = 0;
- *pptr++ = 0;
-
- }
- InvalRect_ImageWindow(true);
-
- } // draw_border
-
- #endif // PHASE_OUT
-
-
- // ==============================================
- // Create and open the virtual image buffer file for large images
- void open_virtual(void)
- {
- int err;
-
- delete_virtual();
-
- if (!gDoingVirtualFile)
- {
- gVirtualImageFile = fopen(POVRAY_IMAGETEMP_FNAME,"wb+");
- err = ferror(gVirtualImageFile);
- }
-
- if (!gVirtualImageFile)
- {
- printf("## Error #%d opening file '%s'!\n", err, POVRAY_IMAGETEMP_FNAME);
- dispose_virtual();
- // no display memory
- DisplayModalDialog(133, ok, 0, NULL, 0, ewcDoCentering, eSameAsPassedWindow);
- }
- else
- {
- gDoingVirtualFile = true;
- }
- } // open_virtual
-
-
- // ==============================================
- // Close and delete the virtual image buffer file
- void delete_virtual(void)
- {
- int k;
- if (gDoingVirtualFile)
- {
- fclose (gVirtualImageFile);
- gVirtualImageFile = NULL;
- }
- k = remove(POVRAY_IMAGETEMP_FNAME);
- gDoingVirtualFile = false;
- } // delete_virtual
-
-
- // ==============================================
- // Dispose of virtual image buffer memory, and close/delete the file
- void dispose_virtual(void)
- {
- delete_virtual();
- gVIBMinY = 32767;
- } // dispose_virtual
-
-
- // ==============================================
- // Calculate VIB indexes from current Y position passed in
- static void CalcVIBSegmentIndexes(short y)
- {
- gVIBCurrSegmentIndex = (int) (y / gVIBPixHeight);
- gVIBMinY = gVIBCurrSegmentIndex * gVIBPixHeight;
- gVIBMaxY = ((gVIBCurrSegmentIndex+1L)*gVIBPixHeight) - 1L;
- }
-
-
- // ==============================================
- // write out the current virtual image buffer to the file
- void write_virtual_segment (void)
- {
- int err;
- PixMapHandle aPixMapH = NULL;
- Ptr aPixPtr;
-
- if (gDoingVirtualFile)
- {
- // Get a handle to the offscreen pixmap struct
- aPixMapH = LockAndLoadPixMap(gOffScreenGWPtr);
- // now get a pointer to the pixmap data
- aPixPtr = GetPixBaseAddr(aPixMapH);
-
- fseek(gVirtualImageFile, (gVIBCurrSegmentIndex * gPixMapBuffSize), SEEK_SET);
- if ( fwrite(aPixPtr, gPixMapBuffSize, 1, gVirtualImageFile) != 1)
- { // error
- err = ferror(gVirtualImageFile);
- if (err)
- printf("## Error #%d writing position #%ld in VIB file '%s'!\n",
- err, (gVIBCurrSegmentIndex * gPixMapBuffSize),
- POVRAY_IMAGETEMP_FNAME);
- dispose_virtual();
- }
- gVIBIsDirty = false;
- // all done with the offscreen pixmap area
- UnlockPixMap(aPixMapH);
- }
- }
-
-
- // ==============================================
- // swap in the "y"th virtual image buffer segment from disk that has "y" scanline
- // (write any old segment first.)
- void swap_virtual_segment (short y)
- {
- int i;
- int err;
- PixMapHandle aPixMapH = NULL;
- Ptr aPixPtr;
-
- // is Y outside currently loaded segment? need to load new one
- if (gDoingVirtualFile && ((y < gVIBMinY) || (y > gVIBMaxY)) )
- {
- // is current segment dirty? save to disk first if so
- if (gVIBIsDirty)
- {
- write_virtual_segment();
- }
-
- // Now calculate and read needed segment into memory
- if (gDoingVirtualFile)
- {
- // calculate new current segment stuff
- CalcVIBSegmentIndexes(y);
-
- // Get a handle to the offscreen pixmap struct
- aPixMapH = LockAndLoadPixMap(gOffScreenGWPtr);
- // now get a pointer to the pixmap data
- aPixPtr = GetPixBaseAddr(aPixMapH);
-
- // read it in off disk
- fseek(gVirtualImageFile, (gVIBCurrSegmentIndex * gPixMapBuffSize), SEEK_SET);
- i = fread(aPixPtr, gPixMapBuffSize, 1, gVirtualImageFile);
- err = ferror(gVirtualImageFile);
- if (err)
- printf("## Error #%d reading position #%ld in VIB file '%s'!\n",
- err, (gVIBCurrSegmentIndex * gPixMapBuffSize),
- POVRAY_IMAGETEMP_FNAME);
- // if freshly loaded from disk, it is not dirty yet
- gVIBIsDirty = false;
-
- // all done with the offscreen pixmap area
- UnlockPixMap(aPixMapH);
- }
-
- // error.. couldn't keep swap file open
- if (!gDoingVirtualFile)
- (void)DisplayModalDialog(139, ok, 0, NULL, 0, ewcDoCentering, eSameAsPassedWindow);
- }
-
- } // swap_virtual_segment
-
-
- // ==============================================
- // Initialize the display, set up buffers (VIB if needed)
- void POV_Mac_Display_Init(int width, int height)
- {
- long freeMemory;
- DialogPtr progressDialogPtr = NULL;
-
- freeMemory = FreeMem();
- if ((**gPrefs2Use_h).progress >= eProgMac)
- {
- printf("-- [Memory] Avail. Memory=%ldKBytes\n", freeMemory/1024L);
- }
-
- // This could take a little while..
- ShowWatchCursor();
-
- gImageWidth = width;
- gImageHeight = height;
- gPixMapBuffSize = CalcPixMapSize(gImageWidth, gImageHeight);
- SetRect(&gImageBounds, 0, 0, width, height);
-
- // NOTE: Due to a limitation of QuickDraw/Pixmaps, a 24-bit color image cannot
- // be bigger than 2047 pixels wide (The pixmap's ROWBYTES field can go up to
- // 8191 bytes, and a 24-bit pixel uses 4 bytes, so 8191/4 = 2047 pixels.)
-
- // So, for really big images, we don't output PICTs, just Targa or PNG.
- // Note that when we rewrite this VIB code to do small squares (banding the
- // image vertically) this will no longer be a problem.
- gTooBigForPICT = (gImageWidth > 2047);
- if (gTooBigForPICT)
- (**gPrefs2Use_h).imageMagFactor = viewmn_hidden;
-
- // if we cannot do an image, or if it is small enough to all fit in RAM...
- if (gTooBigForPICT || (freeMemory > gPixMapBuffSize+100L*1024L))
- { // do the whole image in one offscreen buffer
- gDitherTicks = 20*60; /* 20 seconds between re-dithers */
- }
- else
- { // do the image in segments (VIB mode)
- gDitherTicks = 2L*60L*60L; /* 2 minutes between re-dithers */
-
- // modal dialog up, turn off menus...
- DisableMenus();
-
- // open the VIB file
- open_virtual();
-
- // set up progress dialog
- progressDialogPtr = GetNewProgressDialog(153, 3);
- if (progressDialogPtr)
- {
- PositionWindow(progressDialogPtr, ewcDoCentering, eSameAsPassedWindow, (WindowPtr)gp2wWindow);
- ShowWindow(progressDialogPtr);
- SelectWindow(progressDialogPtr);
- DrawDialog(progressDialogPtr);
- // make sure events get through so dialog is updated
- Cooperate(true);
- Cooperate(true);
- Cooperate(true);
- }
- }
-
- // Allocate the offscreen buffer
- if (!gTooBigForPICT)
- SetupOffscreen();
-
- // let user know some info about the offscreen buffer size
- if ((**gPrefs2Use_h).progress >= eProgMac)
- {
- if (gTooBigForPICT)
- {
- printf("!! [Image] WARNING! This image is too big to display or save as PICT...\n");
- printf("!! it can save as Targa or PNG only.\n");
- }
- else
- {
- // VIB info...
- if (gDoingVirtualFile)
- printf("-- [VIB] VIBNumSegments=%ld, VIBSegmentSize=%ld Kbytes\n",
- 1L+(gImageHeight / gVIBPixHeight), gPixMapBuffSize/1024L);
- // Regular image info
- printf("-- [Image] ImageBufferPixWidth=%ld, ImageBufferPixHeight=%ld, ImageBufferSize=%ld Kbytes\n",
- gImageWidth, gImageHeight, gPixMapBuffSize/1024L);
- }
- }
-
- if (gDoingVirtualFile)
- { // fill the VIB file (pre-swap it)
- if (progressDialogPtr)
- updateProgressDialog(progressDialogPtr, 0, gImageHeight-1, 1);
-
- DrawDialog(progressDialogPtr); // redraw just to be redundant again
-
- // Go through the loop forcing each empty VIB segment to be written to disk,
- // to pre-fill the file.
- {
- int y;
- for (y=0; (y<gImageHeight)&&gDoingVirtualFile; y+=gVIBPixHeight)
- {
- Cooperate(true);
- // Update the progress bar
- if (progressDialogPtr)
- {
- updateProgressDialog(progressDialogPtr, 0, gImageHeight-1, y);
- }
- // force it to write each segment to disk to build the file
- CalcVIBSegmentIndexes(y);
- write_virtual_segment();
- }
- }
-
- // swap back in segment 0
- if (gDoingVirtualFile)
- {
- // force progress bar to go to the end
- if (progressDialogPtr)
- updateProgressDialog(progressDialogPtr, 0, gImageHeight-1, gImageHeight);
- swap_virtual_segment(0);
- }
-
- // get rid of progress dialog
- if (progressDialogPtr)
- disposeProgressDialog(progressDialogPtr);
-
- if (!gDoingVirtualFile) // any errors turned off VIB mode?
- {
- // no disk space for swap file
- (void)DisplayModalDialog(139, ok, 0, NULL, 0, ewcDoCentering, eSameAsPassedWindow);
- dispose_virtual();
- }
-
- // all done being modal...
- EnableMenus(); // re-enable menus
-
- } // VIB mode
-
- if (!gTooBigForPICT)
- {
- // image window now has content
- // turn on now, so SetImageWindMag will show window
- gImageWindIsValid = true;
-
- // Set image window's title
- SetImageWindowTitle(gPictFname);
-
- if (gHasPictUtils)
- SetCustomPalette(false);
- }
-
- // set up next time to repaint
- gRefreshTick = MAC_TICKS;
-
- // size and show the window
- SetImageWindowMag((**gPrefs2Use_h).imageMagFactor);
-
- ShowArrowCursor(); // all done initializing..
-
- } // POV_Mac_Display_Init
-
-
- // ==============================================
- // Plot a single pixel at (x,y)
- void POV_Mac_Display_Plot(int x, int y,
- unsigned int r,
- unsigned int g,
- unsigned int b,
- unsigned int a)
- {
- RGBColor aColor;
- Ptr pixPtr;
- signed char mmuMode;
- Rect magniRect;
- long pport_y;
- int mr;
- int magFactor;
- PixMapHandle aPixMapH = NULL;
-
- // out of range?
- if ((x>=gImageWidth) || (y>=gImageHeight))
- return;
-
- gCurrYPos = y;
-
- if (gOffScreenGWPtr)
- {
- if (gDoingVirtualFile)
- {
- // make sure we've loaded the right segment in
- swap_virtual_segment(y);
- pport_y = y - gVIBMinY; // calculate Y offset within current virtual segment
- gVIBIsDirty = true; // we're about to add to the buffer
- }
- else
- pport_y = y;
-
- #ifdef USE_QUICKDRAW // the way your mother wants you to do it...
- SetPort(gOffScreenGWPtr);
- aColor.red = ((short)r)<<8;
- aColor.green = ((short) g)<<8;
- aColor.blue = ((short) b)<<8;
- if (magFactor == viewmn_normal)
- SetCPixel(x, y, &aColor); // slow, but safe
- #else // the way Chernobog wants you to do it...
- // Get a handle to the offscreen pixmap area
- aPixMapH = LockAndLoadPixMap(gOffScreenGWPtr);
-
- // Calculate a pointer into the Pixmap
- pixPtr = GetPixBaseAddr(aPixMapH); // start at base address
- pixPtr += pport_y*(((**aPixMapH).rowBytes)&0x3fff) // + Y scanline offset down
- + (x*4L); // + X offset over (4 bytes per pixel)
-
- // slam the RGBA values into the pixmap at (x,y)
- mmuMode = true32b;
- SwapMMUMode(&mmuMode);
- *pixPtr = a; pixPtr++;
- *pixPtr = r; pixPtr++;
- *pixPtr = g; pixPtr++;
- *pixPtr = b;
- SwapMMUMode(&mmuMode);
-
- // all done with the offscreen pixmap area
- UnlockPixMap(aPixMapH);
- #endif
- }
- magFactor = (**gPrefs2Use_h).imageMagFactor;
- if (magFactor != viewmn_hidden)
- { // it is visible, display to screen
- // no magnification allowed in VIB mode!
- if (gDoingVirtualFile)
- magFactor = viewmn_normal;
- SetPort(gImageWindowPtr);
- aColor.red = ((short)r)<<8;
- aColor.green = ((short) g)<<8;
- aColor.blue = ((short) b)<<8;
- if (magFactor == viewmn_normal)
- SetCPixel(x, y, &aColor); // slow, but safe
- else
- { // some magnification at play here
- if (magFactor != viewmn_Size2Window)
- { // go to straight magnification N (don't display
- magFactor = magFactor-viewmn_normal+1; // 2,3,4
- mr = gCurrYPos * magFactor;
- magniRect.top = mr;
- magniRect.bottom = mr + magFactor;
- magniRect.left = x * magFactor;
- magniRect.right = (x+1) * magFactor;
- RGBForeColor(&aColor);
- PaintRect(&magniRect);
- }
- }
-
- // time to update the image?
- if (MAC_TICKS > (gRefreshTick + gDitherTicks))
- {
- InvalRect_ImageWindow(false);
- Cooperate(true);
- gRefreshTick = MAC_TICKS;
- }
-
- }
- } // POV_Mac_Display_Plot
-
-
- // ==============================================
- // Plot a rectangle of pixels at (x1,x2,y1,y2)
- void POV_Mac_Display_Plot_Rect (int x1, int x2, int y1, int y2,
- unsigned int r,
- unsigned int g,
- unsigned int b,
- unsigned int a)
- {
- RGBColor aColor;
- Ptr pixPtr;
- signed char mmuMode;
- Rect magniRect;
- int magFactor;
- PixMapHandle aPixMapH = NULL;
-
- // out of range?
- if ((x1>=gImageWidth) || (y1>=gImageHeight))
- return;
-
- gCurrYPos = y1;
-
- magFactor = (**gPrefs2Use_h).imageMagFactor - viewmn_normal + 1; // 1,2,3,4;
- // no magnification allowed in VIB mode!
- if (gDoingVirtualFile)
- magFactor = viewmn_normal;
-
- // make a color record
- aColor.red = ((short)r)<<8;
- aColor.green = ((short) g)<<8;
- aColor.blue = ((short) b)<<8;
-
- // calculate the rect to paint
- x2++; // cheat, stretch out a pixel
- y2++;
- magniRect.top = y1 * magFactor;
- magniRect.bottom = y2 * magFactor;
- magniRect.left = x1 * magFactor;
- magniRect.right = x2 * magFactor;
-
- if (((**gPrefs2Use_h).imageMagFactor != viewmn_hidden)
- && ((**gPrefs2Use_h).imageMagFactor != viewmn_Size2Window))
- { // it is visible, display to screen
- SetPort(gImageWindowPtr);
- RGBForeColor(&aColor);
- PaintRect(&magniRect);
-
- // time to update the entire image?
- if (MAC_TICKS > (gRefreshTick + gDitherTicks))
- {
- InvalRect_ImageWindow(false);
- gRefreshTick = MAC_TICKS;
- }
- }
-
- // Don't write to offscreen in mosaic mode if doing VIB, this is broken and useless,
- // wait till final pass. Who's doing giant images in mosaic mode anyway??? :-)
- if (gDoingVirtualFile)
- return;
-
- if (gOffScreenGWPtr)
- {
- #ifdef NOT_WORKING
- // original 3.0 code, doesn't really work on alpha-channelized gworld!
- SetRect(&magniRect,x1,y1,x2,y2);
- SetPort((GrafPtr)gOffScreenGWPtr);
- RGBForeColor(&aColor);
- PaintRect(&magniRect);
- SetPort(gImageWindowPtr); // exit with image window as curr port
- #else
- /*
- // old 3.0 beta code, worked but slow
- int x,y;
- for (x=x1;x<=x2;x++)
- for (y=y1;y<=y2;y++)
- POV_Mac_Display_Plot(x,y,r,g,b,a);
- */
- int x,y,xm,ym;
- // Get a handle to the offscreen pixmap area
- aPixMapH = LockAndLoadPixMap(gOffScreenGWPtr);
- // loop down scanlines
- ym=(y2>=gImageHeight)?gImageHeight-1:y2; // pin at edge
- for (y=y1;y<ym;y++)
- {
- // Calculate a pointer into the Pixmap
- pixPtr = GetPixBaseAddr(aPixMapH); // start at base address
- pixPtr += y*(((**aPixMapH).rowBytes)&0x3fff) // + Y scanline offset down
- + (x1*4L); // + X offset over (4 bytes per pixel)
- mmuMode = true32b;
- SwapMMUMode(&mmuMode);
- // loop across pixels on this line
- xm=(x2>=gImageWidth)?gImageWidth-1:x2; // pin at edge
- for (x=x1;x<xm;x++)
- {
- // slam the RGBA values into the pixmap at (x,y)
- *pixPtr = a; pixPtr++;
- *pixPtr = r; pixPtr++;
- *pixPtr = g; pixPtr++;
- *pixPtr = b; pixPtr++;
- }
- SwapMMUMode(&mmuMode);
- }
-
- // all done with the offscreen pixmap area
- UnlockPixMap(aPixMapH);
-
- #endif
- }
-
- } // POV_Mac_Display_Plot_Rect
-
-
-
- // ==============================================
- // Do any cleanup needed when the display is complete
- void POV_Mac_Display_Finished(void)
- {
- // Reset last Y pos so that screen refreshes do the whole screen
- gLastYPos = -1;
- } // POV_Mac_Display_Finished
-
-
- // ==============================================
- // Close any files used after display is complete
- void POV_Mac_Display_Close(void)
- {
- } // POV_Mac_Display_Close
-
-
- // ==============================================
- // Find and assign the appropriate custom palette to the image window
- void SetCustomPalette(Boolean doScreenUpdate)
- {
- PictInfo plot_info;
- short k;
- OSErr anError = noErr;
- PaletteHandle thePalette = NULL;
-
- if (gImageWindowPtr)
- SetPort(gImageWindowPtr);
-
- if (gHasPictUtils && gUsingCustomPalette && gOffScreenGWPtr)
- {
- switch(gColorQuantMethod)
- {
- case systemMethod:
- case popularMethod:
- case medianMethod:
- {
- PixMapHandle aPixMapH = NULL;
- // Get a handle to the offscreen pixmap area
- aPixMapH = LockAndLoadPixMap(gOffScreenGWPtr);
- anError = GetPixMapInfo(aPixMapH,
- &plot_info,
- returnPalette + suppressBlackAndWhite,
- 256,
- gColorQuantMethod,
- 0);
- // all done with the offscreen pixmap area
- UnlockPixMap(aPixMapH);
-
- // copy the new palette entries into custom palette & use it
- if (plot_info.thePalette && gCustomPalette)
- {
- CopyPalette(plot_info.thePalette, gCustomPalette, 0, 0, 256);
- for (k=0; k<256; k++)
- SetEntryUsage(gCustomPalette, k, pmTolerant, 0x0000);
- thePalette = gCustomPalette;
- }
- // done with retrieved palette. toolbox created it, so we must destroy it!
- if (plot_info.thePalette)
- DisposePalette(plot_info.thePalette);
- break;
- }
- otherwise:
- SysBeep(4);
- break;
- }
- }
- else
- {
- // Revert to system palette
- thePalette = gSystemPalette;
- }
-
- if (gImageWindowPtr)
- {
- // reset all screens, this is a little severe though!
- if (doScreenUpdate)
- RestoreDeviceClut(NULL);
- // tell window to use the new palette
- if (thePalette)
- NSetPalette(gImageWindowPtr, thePalette, pmAllUpdates);
- ActivatePalette(gImageWindowPtr);
- }
-
- } // SetCustomPalette
-
-
-
-
- // ==============================================
- // Write Picture bottleneck routine for paint_to_picture()
- static pascal void MyPutPicProc(char *dataPtr, short byteCount)
- {
- size_t myByteCount;
-
- myByteCount = byteCount;
- gMyPicSize += byteCount;
- if (gImagePictFile)
- {
- if (fwrite( dataPtr, 1, myByteCount, gImagePictFile) != myByteCount)
- {
- fclose (gImagePictFile);
- gImagePictFile = NULL;
- SysBeep(3);
- }
- }
- // we have to keep the picture handle header updated for Quickdraw!
- if (gMyPicHandle)
- (**gMyPicHandle).picSize = gMyPicSize;
- } // MyPutPicProc
-
-
-
- // ==============================================
- // Write the Pixmap out to either an open disk file, or the Clipboard
- void paint_to_picture(short do_disk_buffer)
- {
- short myMode, i;
- OSErr anError=noErr;
- Rect my_bounds, myPicRect;
- CGrafPort myCGrafPort;
- GrafPtr oldGrafPtr;
- PictFHeader myPictFHeader;
- CQDProcsPtr oldQDProcs;
- CQDProcs myQDProcs;
- QDPutPicUPP myDrawProcUPP;
- PixMapHandle aPixMapH = NULL;
-
- if (gOffScreenGWPtr)
- {
- ShowWatchCursor(); // could take a little while..
-
- GetPort(&oldGrafPtr);
- OpenCPort (&myCGrafPort);
- SetPort ((GrafPtr)&myCGrafPort);
-
- PortSize (gImageWidth, gImageHeight);
- myPicRect.top = 0;
- myPicRect.bottom = gImageHeight;
- myPicRect.left = 0;
- myPicRect.right = gImageWidth;
-
- if (do_disk_buffer)
- {
- // remember old bottlenecks for restoring later
- oldQDProcs = myCGrafPort.grafProcs;
- // Fill our custom rec with standard Color bottleneck procs
- SetStdCProcs ( &myQDProcs);
- // create ProcPtr of our custom proc
- myDrawProcUPP = NewQDPutPicProc(MyPutPicProc);
- // stick our new PutPic bottleneck proc in
- myQDProcs.putPicProc = myDrawProcUPP;
- // stick new methods back into QD Grafport
- myCGrafPort.grafProcs = &myQDProcs;
- // write the PICT header to the file
- gMyPicSize = sizeof(myPictFHeader);
- // set up header fields
- myPictFHeader.picSize = gMyPicSize; // incremented later in MyPutPicProc()..
- myPictFHeader.picFrame = myPicRect;
- // write header
- i = fwrite (&myPictFHeader, 1, sizeof(myPictFHeader), gImagePictFile);
- anError = ferror(gImagePictFile);
- }
-
- if (!anError)
- {
- /* insure gMyPicHandle null, 'cause MyPutPicProc will be called in OpenPicture! */
- gMyPicHandle = NULL;
- gMyPicHandle = OpenPicture (&myPicRect);
- anError = QDError();
- }
-
- if ((**gPrefs2Use_h).doDither)
- myMode = ditherCopy;
- else
- myMode = srcCopy;
-
- if (!anError)
- {
- RGBColor myRGBWhite = {-1,-1,-1};
- RGBColor myRGBBlack = {0,0,0};
-
- ClipRect(&myPicRect);
- // set these to defaults so copybits behaves predictably
- RGBBackColor(&myRGBWhite);
- RGBForeColor(&myRGBBlack);
-
- if (gDoingVirtualFile)
- {
- for (i=0; (i <= gImageHeight) && !anError; i+= gVIBPixHeight)
- {
- swap_virtual_segment (i);
- // set left/right
- my_bounds = gImageBounds;
- // set top/bottom
- my_bounds.top = i;
- // NOTE, JIM! (next source line)
- // By doing a CopyBits of the last rect in full, the whole rect of pixels _does_
- // get written to the PICT file, even though not all the scan lines are valid..
- // this doesn't hurt anything, just makes the file a little bigger than it needs to be,
- // since the extra lines will get clipped on playback. However, since gImageBounds is
- // global, it would be icky to temporarily change its bottom along with my_bounds so
- // as to only write the necessary lines.. maybe later. [esp] :-)
- my_bounds.bottom = my_bounds.top + gVIBPixHeight;
- // Get a handle to the offscreen pixmap area
- aPixMapH = LockAndLoadPixMap(gOffScreenGWPtr);
- CopyBits((BitMap*)*aPixMapH, (BitMap*)&myCGrafPort.portPixMap,
- &gImageBounds, &my_bounds,
- myMode, NULL);
- anError = QDError();
- // all done with the offscreen pixmap area
- UnlockPixMap(aPixMapH);
- }
- }
- else
- {
- // Get a handle to the offscreen pixmap area
- aPixMapH = LockAndLoadPixMap(gOffScreenGWPtr);
- CopyBits((BitMap*)*aPixMapH, (BitMap*)&myCGrafPort.portPixMap,
- &gImageBounds, &gImageBounds,
- myMode, NULL);
- anError = QDError();
- // all done with the offscreen pixmap area
- UnlockPixMap(aPixMapH);
- }
-
-
- }
-
- /* write end-of-picture */
- if (!anError)
- {
- ClosePicture();
- anError = QDError();
- }
-
- if (!anError)
- {
- if (do_disk_buffer)
- {
- // restore old bottlenecks
- myCGrafPort.grafProcs = oldQDProcs;
- DisposeRoutineDescriptor(myDrawProcUPP);
-
- /* move back to pic header again */
- if (gImagePictFile)
- {
- fflush(gImagePictFile);
- fseek(gImagePictFile, PICTF_HEADER_SIZE, SEEK_SET);
- anError = ferror(gImagePictFile);
- }
- /* update the PICT header in the file (with now-true picSize field..) */
- if (!anError && gImagePictFile)
- {
- myPictFHeader.picSize = gMyPicSize;
- i = fwrite (&myPictFHeader, 1, sizeof(myPictFHeader), gImagePictFile);
- anError = ferror(gImagePictFile);
- }
- }
- else
- {
- ZeroScrap();
- HLock((Handle) gMyPicHandle);
- gMyPicSize = GetHandleSize((Handle) gMyPicHandle);
- PutScrap (gMyPicSize, 'PICT', (Ptr) *gMyPicHandle);
- gMyPicSize = UnloadScrap();
- HUnlock((Handle) gMyPicHandle);
- }
- } // if !error
-
- /* close up shop */
- CloseCPort(&myCGrafPort);
- SetPort(oldGrafPtr);
- if (gMyPicHandle)
- DisposeHandle((Handle) gMyPicHandle);
-
- /* oh yeah, check for errors */
- if (anError)
- {
- if (gImagePictFile)
- {
- fclose (gImagePictFile);
- gImagePictFile = NULL;
- }
- SysBeep(4);
- }
-
- ShowArrowCursor();
-
- } // if gOffScreenGWPtr..
-
- } // paint_to_picture
-
-
- // ==============================================
- // Write the Pixmap as a PICT file
- // getName - if true, prompt for output file name
- // ci - QuickTime StdCompression component if image is to be compressed
- void SaveOutputFile(Boolean getName, ComponentInstance ci)
- {
- int k;
- Rect myPicRect;
- Point where;
- SFReply reply;
- FInfo myFileInfo;
- FSSpec fsFile;
- long filler;
-
- // It is possible (via Cooperate) that we could be in here saving an image,
- // and the silly user could hit SAVE again, getting us in here again on top
- // of the previous save. This causes a file save error. Instead, we check
- // here to see if we're already in here, and we beep and return if so.
- // (Thanks Adam for finding this one!)
- if (gBusySavingImage)
- {
- SysBeep(1);
- return;
- }
- gBusySavingImage = TRUE;
-
- //
- // Get the name of the file, or just get existing name as is
- //
- if (getName)
- {
- GetBestDialogPos(&where, (WindowPtr)&gp2wWindow);
- SFPutFile (where, "\pSave Pict file as…", gPictFname, NULL, &reply);
- }
- else
- {
- // copy the existing name into SF Reply..
- BlockMoveData(gPictFname, (char *) reply.fName, 1+gPictFname[0]);
- reply.vRefNum = gSrcWind_VRefNum;
- reply.good = TRUE;
- }
-
- //
- // Now save the file
- //
- if (reply.good)
- {
- ShowWatchCursor();
-
- // build an FSSpec
- fsFile.vRefNum = reply.vRefNum;
- fsFile.parID = 0;
- BlockMove(reply.fName, fsFile.name, 1+reply.fName[0]);
-
- // delete any previous file first
- FSpDelete(&fsFile);
-
- // prepare for C-style file I/O, set current directory
- p2cstr(reply.fName);
- SetVol(NULL, reply.vRefNum);
-
- // create new file
- gImagePictFile = fopen((char *) reply.fName,"wb");
- if (gImagePictFile)
- {
- // prepare a little buffer of zeroes to write out header
- filler = 0;
- // write 512 bytes of zeroes to fill the header
- for (k=0; k<PICTF_HEADER_SIZE/4; k++)
- fwrite (&filler, 1, 4, gImagePictFile);
-
- // if not doing a virtual screen (which could take awhile) then
- // let the window update event get through to repaint the image
- // in case the dialog stomped on it.
- if (!gDoingVirtualFile)
- {
- Cooperate(true);
- }
-
- paint_to_picture(true);
-
- if (gImagePictFile)
- {
- fclose (gImagePictFile);
- gImagePictFile = NULL;
- c2pstr((char *)reply.fName);
-
- /* If QuickTime is around & user wants to squish the picture, ask user how to squish it */
- k = FSMakeFSSpec(reply.vRefNum, 0, reply.fName, &fsFile);
- if (gHasImageCompressionMgr && (**gPrefs2Use_h).doPictCompression)
- {
- myPicRect.top = 0;
- myPicRect.bottom = gImageHeight;
- myPicRect.left = 0;
- myPicRect.right = gImageWidth;
- k=CompressPictF(ci, &fsFile);
- }
-
- // set image file to type PICT
- k = FSpGetFInfo(&fsFile, &myFileInfo);
- if (k==noErr)
- {
- myFileInfo.fdType = 'PICT';
- myFileInfo.fdCreator = (**gPrefs2Use_h).pictFileCreator;
- // turn OFF inited flag, so Finder refreshes file information
- myFileInfo.fdFlags &= ~kHasBeenInited;
- k = FSpSetFInfo(&fsFile, &myFileInfo);
- }
-
- // not yet tested and working, but leave in for later..
- // // stick a preview resource on it
- // if (wanted..)
- // k = AppendFilePreview2PictF(&fsFile);
-
- // Add System 7 custom icons of the image itself to the file
- if (gHasImageCompressionMgr && APGet_AddCustomIcons())
- AppendFinderIcons2PictF(&fsFile, &myPicRect, eAFI_ShrinkWholeImage);
- }
- else
- // couldn't write PICT file
- (void)DisplayModalDialog(140, ok, 0, NULL, 0, ewcDoCentering, eSameAsPassedWindow);
- }
- ShowArrowCursor();
- }
- gBusySavingImage = FALSE;
- } // SaveOutputFile
-
-